package com.tianqi.modules.pms.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.nlf.calendar.Lunar;
import com.tianqi.common.constant.GuaConstant;
import com.tianqi.common.enums.*;
import com.tianqi.common.exception.ApiException;
import com.tianqi.common.utils.LunarDateUtil;
import com.tianqi.modules.pms.dto.request.LiuYaoReq;
import com.tianqi.modules.pms.dto.response.*;
import com.tianqi.modules.pms.service.LiuYaoService;
import com.tianqi.modules.tqs.constant.RelationMapConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 六爻相关接口实现类
 *
 * @author zhangzedi
 * @date 2023/8/19 16:24
 **/
@Service
@Slf4j
public class LiuYaoServiceImpl implements LiuYaoService {

	@Autowired
	private LunarDateUtil lunarDateUtil;

	/**
	 * 根据六爻梅花参数查询卦象
	 *
	 * @param liuYaoReq
	 * @return
	 */
	@Override
	public LiuYaoAllResp queryLiuYaoGua(LiuYaoReq liuYaoReq) {
		log.info("开始计算六爻");
		long startMills = System.currentTimeMillis();
		// 返回参数
		LiuYaoAllResp liuYaoAllResp = new LiuYaoAllResp();
		List<LiuYaoGua> liuYaoGuaList = new ArrayList<>(5);
		// 根据起卦方法获取主卦
		LiuYaoGua mainGua = getGuaByReq(liuYaoReq);
		liuYaoGuaList.add(mainGua);
		// 根据主卦获取互卦
		LiuYaoGua huGua = getHuGua(mainGua);
		liuYaoGuaList.add(huGua);
		// 根据主卦获取变卦
		LiuYaoGua changeGua = getChangeGua(mainGua);
		liuYaoGuaList.add(changeGua);
		// 根据主卦获取错卦
		LiuYaoGua cuoGua = getCuoGua(mainGua);
		liuYaoGuaList.add(cuoGua);
		// 根据主卦获取综卦
		LiuYaoGua zongGua = getZongGua(mainGua);
		liuYaoGuaList.add(zongGua);
		liuYaoAllResp.setLiuYaoGuaList(liuYaoGuaList);
		// 装换占时为农历
		Lunar divineLunar = lunarDateUtil.formatEightChar(liuYaoReq.getDivineTime());
		// 获取主卦的天干地支等
		List<ZhuGuaGanZhi> zhuGuaGanZhiList = getZhuGuaGanZhi(mainGua, divineLunar);
		liuYaoAllResp.setZhuGuaGanZhiList(zhuGuaGanZhiList);
		// 获取伏中变色的六亲
		List<String> fuChangeColorLiuQin = getFuChangeColorLiuQin(zhuGuaGanZhiList);
		liuYaoAllResp.setFuDisColorLiuQin(fuChangeColorLiuQin);
		// 获取藏中变色的六亲
		List<String> cangChangeColorLiuQin = getCangChangeColorLiuQin(zhuGuaGanZhiList);
		liuYaoAllResp.setCangDisColorLiuQin(cangChangeColorLiuQin);
		// 获取变卦的天干地支等
		List<ChangeGuaGanZhi> changeGuaGanZhiList = getChangeGuaGanZhi(changeGua, divineLunar);
		liuYaoAllResp.setChangeGuaGanZhiList(changeGuaGanZhiList);
		// 设置主卦卦身，卦名等
		setMainGuaGong(liuYaoAllResp, mainGua, changeGua);
		long endMillis = System.currentTimeMillis();
		log.info("接口调用时间为：{}毫秒", endMillis - startMills);
		return liuYaoAllResp;
	}


	/**
	 * 查询小成图
	 *
	 * @param liuYaoReq
	 * @return
	 */
	@Override
	public XiaoChengTuResp queryXiaoChengTu(LiuYaoReq liuYaoReq) {
		log.info("开始计算小成图");
		long startMills = System.currentTimeMillis();
		XiaoChengTuResp xiaoChengTuResp = new XiaoChengTuResp();
		// 根据起卦方法获取主卦
		LiuYaoGua mainGua = getGuaByReq(liuYaoReq);
		// 根据主卦获取互卦
		LiuYaoGua huGua = getHuGua(mainGua);
		// 根据主卦获取变卦
		LiuYaoGua changeGua = getChangeGua(mainGua);
		// 获取变卦的互卦
		LiuYaoGua changeHuGua = getHuGua(changeGua);
		// 设置卦位，从1到8分别是,1-变卦互卦的下卦,2-主卦的下卦,3-变卦互卦的上卦,4-变卦的上卦
		// 5-互卦的上卦，6-主卦的上卦,7-互卦的下卦，8-变卦的下卦
		xiaoChengTuResp.setGua1(changeHuGua.getDownGua());
		xiaoChengTuResp.setGua2(mainGua.getDownGua());
		xiaoChengTuResp.setGua3(changeHuGua.getUpGua());
		xiaoChengTuResp.setGua4(changeGua.getUpGua());
		xiaoChengTuResp.setGua5(huGua.getUpGua());
		xiaoChengTuResp.setGua6(mainGua.getUpGua());
		xiaoChengTuResp.setGua7(huGua.getDownGua());
		xiaoChengTuResp.setGua8(changeGua.getDownGua());
		// 计算归藏
		BaseGuaEnum mainGuiCangGua = getGuiCangGua(mainGua.getUpGua(), mainGua.getDownGua());
		BaseGuaEnum changeGuiCangGua = getGuiCangGua(changeGua.getUpGua(), changeGua.getDownGua());
		if (liuYaoReq.getGuiCangNum() == null) {
			throw new ApiException("请输入归藏次数");
		}
		// 判断归藏次数
		if (liuYaoReq.getGuiCangNum() == 1) {
			xiaoChengTuResp.setMainGuiCangGua(mainGuiCangGua);
			xiaoChengTuResp.setChangeGuiCangGua(changeGuiCangGua);
		} else if (liuYaoReq.getGuiCangNum() == 2) {
			// 再次归藏
			BaseGuaEnum twoGuiCangGua = getGuiCangGua(mainGuiCangGua, changeGuiCangGua);
			xiaoChengTuResp.setMainGuiCangGua(twoGuiCangGua);
		} else {
			throw new ApiException("归藏次数输入不正确");
		}

		long endMillis = System.currentTimeMillis();
		log.info("接口调用时间为：{}毫秒", endMillis - startMills);
		return xiaoChengTuResp;
	}

	/**
	 * 根据参数计算主卦
	 *
	 * @param liuYaoReq
	 * @return
	 */
	private LiuYaoGua getGuaByReq(LiuYaoReq liuYaoReq) {
		LiuYaoGua main = new LiuYaoGua();
		LiuYaoReqEnum type = LiuYaoReqEnum.findQiGuaType(liuYaoReq.getType());
		if (type == null) {
			throw new ApiException("参数类型不正确");
		}
		BaseGuaEnum upGua, downGua;
		// 变动位置以及变动方式，1-阳变阴，0-阴变阳
		List<ChangeGua> changeList;
		int up, down, change;
		if (type == LiuYaoReqEnum.SANSHU_A || type == LiuYaoReqEnum.SANSHU_B
				|| type == LiuYaoReqEnum.SHUANGSHU_A || type == LiuYaoReqEnum.SHUANGSHU_B) {
			// 三数和双数计算上下卦的方法相同,只是计算动爻的方法不同
			// 取第一个参数除以8的余数为上卦
			up = liuYaoReq.getParam1() % 8;
			// 如果余数为0，则取第八个
			if (up == 0) {
				up = 8;
			}
			upGua = BaseGuaEnum.findGuaByIndex(up);
			main.setUpGua(upGua);
			// 取第二个参数除以8的余数为8为下卦
			down = liuYaoReq.getParam2() % 8;
			// 如果余数为0，则取第八个
			if (down == 0) {
				down = 8;
			}
			downGua = BaseGuaEnum.findGuaByIndex(down);
			main.setDownGua(downGua);
			if (type == LiuYaoReqEnum.SANSHU_A) {
				// 取第三个数除以6的余数为动爻
				change = liuYaoReq.getParam3() % 6;
				// 如果余数为0，则取第六个
				if (change == 0) {
					change = 6;
				}
			} else if (type == LiuYaoReqEnum.SANSHU_B) {
				// 取三个数的和除以6的余数为动爻
				change = (liuYaoReq.getParam1() + liuYaoReq.getParam2() + liuYaoReq.getParam3()) % 6;
				// 如果余数为0，则取第六个
				if (change == 0) {
					change = 6;
				}
			} else if (type == LiuYaoReqEnum.SHUANGSHU_A) {
				// 取两个数的和除以6的余数为动爻位置
				change = (liuYaoReq.getParam1() + liuYaoReq.getParam2()) % 6;
				// 如果余数为0，则取第六个
				if (change == 0) {
					change = 6;
				}
			} else {
				// 取两个数的和再加上时辰除以6的余数为动爻位置
				// 获取现在的时间
				Lunar lunar = Lunar.fromDate(DateUtil.date());
				// 取两个数的和除以6的余数为动爻位置
				change = (liuYaoReq.getParam1() + liuYaoReq.getParam2() + lunar.getTimeZhiIndex() + 1) % 6;
				// 如果余数为0，则取第六个
				if (change == 0) {
					change = 6;
				}
			}
			ChangeGua changeGua = new ChangeGua();
			changeGua.setIndex(change);
			// 查询动爻所在位置的阴阳
			if (change > 3) {
				// 在上卦
				if (change == 4) {
					change = 2;
				} else if (change == 5) {
					change = 1;
				} else {
					change = 0;
				}
				if (GuaConstant.YANG == upGua.getYaos().charAt(change)) {
					// 为阳变阴
					changeGua.setType(1);
				} else {
					// 为阴变阳
					changeGua.setType(0);
				}
			} else {
				// 在下卦
				if (change == 1) {
					change = 2;
				} else if (change == 2) {
					change = 1;
				} else {
					change = 0;
				}
				if (GuaConstant.YANG == downGua.getYaos().charAt(change)) {
					// 为阳变阴
					changeGua.setType(1);
				} else {
					// 为阴变阳
					changeGua.setType(0);
				}
			}
			changeList = new ArrayList<>(1);
			changeList.add(changeGua);
			main.setChangeList(changeList);
		} else if (type == LiuYaoReqEnum.YINGBI || type == LiuYaoReqEnum.TONGQIAN) {
			// 上卦的参数是4,5,6
			LiuYaoGuaEnum yao4 = LiuYaoGuaEnum.findGuaByType(liuYaoReq.getParam4());
			LiuYaoGuaEnum yao5 = LiuYaoGuaEnum.findGuaByType(liuYaoReq.getParam5());
			LiuYaoGuaEnum yao6 = LiuYaoGuaEnum.findGuaByType(liuYaoReq.getParam6());
			// 下卦的参数是1,2,3
			LiuYaoGuaEnum yao1 = LiuYaoGuaEnum.findGuaByType(liuYaoReq.getParam1());
			LiuYaoGuaEnum yao2 = LiuYaoGuaEnum.findGuaByType(liuYaoReq.getParam2());
			LiuYaoGuaEnum yao3 = LiuYaoGuaEnum.findGuaByType(liuYaoReq.getParam3());
			if (yao1 == null || yao2 == null || yao3 == null || yao4 == null || yao5 == null || yao6 == null) {
				throw new ApiException("起卦参数不正确");
			}
			// 根据上三爻查到上卦
			upGua = BaseGuaEnum.findGuaByYao(yao6.getYang(), yao5.getYang(), yao4.getYang());
			main.setUpGua(upGua);
			// 根据下三爻查询下卦
			downGua = BaseGuaEnum.findGuaByYao(yao3.getYang(), yao2.getYang(), yao1.getYang());
			main.setDownGua(downGua);
			// 判断各个爻是否为动爻
			changeList = new ArrayList<>(6);
			if (yao1.getChange()) {
				// 获取阴阳
				ChangeGua changeGua = new ChangeGua();
				changeGua.setIndex(1);
				changeGua.setType(Integer.valueOf(yao1.getYang()));
				changeList.add(changeGua);
			}
			if (yao2.getChange()) {
				// 获取阴阳
				ChangeGua changeGua = new ChangeGua();
				changeGua.setIndex(2);
				changeGua.setType(Integer.valueOf(yao2.getYang()));
				changeList.add(changeGua);
			}
			if (yao3.getChange()) {
				// 获取阴阳
				ChangeGua changeGua = new ChangeGua();
				changeGua.setIndex(3);
				changeGua.setType(Integer.valueOf(yao3.getYang()));
				changeList.add(changeGua);
			}
			if (yao4.getChange()) {
				// 获取阴阳
				ChangeGua changeGua = new ChangeGua();
				changeGua.setIndex(4);
				changeGua.setType(Integer.valueOf(yao4.getYang()));
				changeList.add(changeGua);
			}
			if (yao5.getChange()) {
				ChangeGua changeGua = new ChangeGua();
				changeGua.setIndex(5);
				changeGua.setType(Integer.valueOf(yao5.getYang()));
				changeList.add(changeGua);
			}
			if (yao6.getChange()) {
				ChangeGua changeGua = new ChangeGua();
				changeGua.setIndex(6);
				changeGua.setType(Integer.valueOf(yao6.getYang()));
				changeList.add(changeGua);
			}
			main.setChangeList(changeList);
		}
		return main;
	}

	/**
	 * 根据卦以及改变位置，计算变卦
	 *
	 * @param liuYaoReq
	 * @return
	 */
	private LiuYaoGua getChangeGua(LiuYaoGua liuYaoReq) {
		LiuYaoGua changeGua = new LiuYaoGua();
		// 先判断是否存在变卦
		if (CollectionUtil.isEmpty(liuYaoReq.getChangeList())) {
			// 如果不存在，则主卦就是变卦
			return liuYaoReq;
		}
		// 获取动爻位置
		List<Integer> indexList =
				liuYaoReq.getChangeList().stream().map(ChangeGua::getIndex).collect(Collectors.toList());
		String oldUpGuaStr;
		// 新的上卦，初始化赋值老的上卦字符串
		String newUpGuaStr = liuYaoReq.getUpGua().getYaos();
		String oldDownGuaStr;
		// 新的下卦，初始化赋值老的下卦字符串
		String newDownGuaStr = liuYaoReq.getDownGua().getYaos();
		char changYao;
		BaseGuaEnum newUpGua, newDownGua;
		for (Integer index : indexList) {
			// 判断index的位置
			if (index > 3) {
				if (index == 4) {
					index = 2;
				} else if (index == 5) {
					index = 1;
				} else {
					index = 0;
				}
				changYao = newUpGuaStr.charAt(index);
				oldUpGuaStr = newUpGuaStr;
				//阴阳互换
				changYao = interchangeYinYang(changYao);
				// 重新拼装为新的上卦
				if (index == 2) {
					newUpGuaStr = oldUpGuaStr.substring(0, index) + changYao;
				} else {
					newUpGuaStr = oldUpGuaStr.substring(0, index) + changYao + oldUpGuaStr.substring(index + 1);
				}
			} else {
				if (index == 1) {
					index = 2;
				} else if (index == 2) {
					index = 1;
				} else {
					index = 0;
				}
				changYao = newDownGuaStr.charAt(index);
				oldDownGuaStr = newDownGuaStr;
				//阴阳互换
				changYao = interchangeYinYang(changYao);
				// 重新拼装为新的下卦
				if (index == 2) {
					newDownGuaStr = oldDownGuaStr.substring(0, index) + changYao;
				} else {
					newDownGuaStr = oldDownGuaStr.substring(0, index) + changYao + oldDownGuaStr.substring(index + 1);
				}
			}
		}
		newUpGua = BaseGuaEnum.findGuaByYaos(newUpGuaStr);
		newDownGua = BaseGuaEnum.findGuaByYaos(newDownGuaStr);
		changeGua.setUpGua(newUpGua);
		changeGua.setDownGua(newDownGua);
		return changeGua;
	}

	/**
	 * 阴阳互换
	 *
	 * @param c
	 * @return
	 */
	private char interchangeYinYang(char c) {
		//阳变阴，阴变阳
		if (c == GuaConstant.YANG) {
			c = GuaConstant.YIN;
		} else {
			c = GuaConstant.YANG;
		}
		return c;
	}

	/**
	 * 计算输入卦的互卦
	 *
	 * @param mainGua
	 * @return
	 */
	private LiuYaoGua getHuGua(LiuYaoGua mainGua) {
		LiuYaoGua huGua = new LiuYaoGua();
		//上卦
		BaseGuaEnum upGua = mainGua.getUpGua();
		//下卦
		BaseGuaEnum downGua = mainGua.getDownGua();
		// 互卦的上卦为原来卦的，三四五，爻
		String newUpGuaStr = upGua.getYaos().substring(1) + downGua.getYaos().charAt(0);
		// 互卦的下卦为原来卦的，二三四爻
		String newDownGuaStr = upGua.getYaos().substring(2) + downGua.getYaos().substring(0, 2);
		huGua.setUpGua(BaseGuaEnum.findGuaByYaos(newUpGuaStr));
		huGua.setDownGua(BaseGuaEnum.findGuaByYaos(newDownGuaStr));
		return huGua;
	}

	/**
	 * 计算输入卦的错卦
	 *
	 * @param mainGua
	 * @return
	 */
	private LiuYaoGua getCuoGua(LiuYaoGua mainGua) {
		LiuYaoGua huGua = new LiuYaoGua();
		//上卦
		BaseGuaEnum upGua = mainGua.getUpGua();
		//下卦
		BaseGuaEnum downGua = mainGua.getDownGua();
		// 错卦为根据之前卦变成完全相反的爻
		char upYao6 = interchangeYinYang(upGua.getYaos().charAt(0));
		char upYao5 = interchangeYinYang(upGua.getYaos().charAt(1));
		char upYao4 = interchangeYinYang(upGua.getYaos().charAt(2));
		String newUpGuaStr = upYao6 + String.valueOf(upYao5) + upYao4;
		char yao3 = interchangeYinYang(downGua.getYaos().charAt(0));
		char yao2 = interchangeYinYang(downGua.getYaos().charAt(1));
		char yao1 = interchangeYinYang(downGua.getYaos().charAt(2));
		String newDownGuaStr = String.valueOf(yao3) + yao2 + yao1;
		huGua.setUpGua(BaseGuaEnum.findGuaByYaos(newUpGuaStr));
		huGua.setDownGua(BaseGuaEnum.findGuaByYaos(newDownGuaStr));
		return huGua;
	}

	/**
	 * 计算输入卦的综卦
	 *
	 * @param mainGua
	 * @return
	 */
	private LiuYaoGua getZongGua(LiuYaoGua mainGua) {
		LiuYaoGua huGua = new LiuYaoGua();
		//上卦
		BaseGuaEnum upGua = mainGua.getUpGua();
		//下卦
		BaseGuaEnum downGua = mainGua.getDownGua();
		// 综卦为根据之前卦变成从下往下数颠倒一下
		char yao6 = upGua.getYaos().charAt(0);
		char yao5 = upGua.getYaos().charAt(1);
		char yao4 = upGua.getYaos().charAt(2);
		char yao3 = downGua.getYaos().charAt(0);
		char yao2 = downGua.getYaos().charAt(1);
		char yao1 = downGua.getYaos().charAt(2);
		String newUpGuaStr = String.valueOf(yao1) + yao2 + yao3;
		String newDownGuaStr = String.valueOf(yao4) + yao5 + yao6;
		huGua.setUpGua(BaseGuaEnum.findGuaByYaos(newUpGuaStr));
		huGua.setDownGua(BaseGuaEnum.findGuaByYaos(newDownGuaStr));
		return huGua;
	}

	/**
	 * 主卦的干支伏藏等详情
	 *
	 * @return
	 */
	private List<ZhuGuaGanZhi> getZhuGuaGanZhi(LiuYaoGua mainGua, Lunar lunar) {
		List<ZhuGuaGanZhi> zhuGuaGanZhiList = new ArrayList<>();
		// 组合卦的下标
		String mergeIndex = String.valueOf(mainGua.getUpGua().getIndex()) + mainGua.getDownGua().getIndex();
		// 获取日干的六神
		DayLiuShenEnum dayLiuShenEnum = DayLiuShenEnum.getLiuQinByIndex(lunar.getDayGan());
		if (dayLiuShenEnum == null) {
			throw new ApiException("获取日干六神失败");
		}
		// 获取藏的天干等信息
		GuaCangGanZhiEnum guaCangGanZhiEnum = GuaCangGanZhiEnum.getGanZhiByIndex(mergeIndex);
		if (guaCangGanZhiEnum == null) {
			throw new ApiException("获取藏的干支失败");
		}
		// 获取伏的天干等信息
		GuaFuGanZhiEnum guaFuGanZhiEnum = GuaFuGanZhiEnum.getGanZhiByIndex(mergeIndex);
		if (guaFuGanZhiEnum == null) {
			throw new ApiException("获取伏的干支失败");
		}
		// 获取卦的主要天干等信息
		GuaMainGanZhiEnum guaMainGanZhiEnum = GuaMainGanZhiEnum.getGanZhiByIndex(mergeIndex);
		if (guaMainGanZhiEnum == null) {
			throw new ApiException("获取卦主要的干支失败");
		}
		// 获取卦的六亲关系
		GuaLiuQinEnum guaLiuQinEnum = GuaLiuQinEnum.getLiuQinByIndex(mergeIndex);
		if (guaLiuQinEnum == null) {
			throw new ApiException("获取卦的六亲失败");
		}
		for (int index = 1; index <= 6; index++) {
			ZhuGuaGanZhi zhuGuaGanZhi = new ZhuGuaGanZhi();
			String liuShen = dayLiuShenEnum.getLiuShen(index);
			zhuGuaGanZhi.setLiuShen(liuShen);
			// 设置六神简称
			zhuGuaGanZhi.setLiuShenSimple(FulInitialsBeloEnum.getValueByelEment("六神", liuShen).getAbbreviation());
			// 设置藏相关参数
			String cangGanZhi = guaCangGanZhiEnum.getCangGanZhi(index);
			zhuGuaGanZhi.setCangTianGan(cangGanZhi.substring(0, 1));
			zhuGuaGanZhi.setCangDiZhi(cangGanZhi.substring(1, 2));
			zhuGuaGanZhi.setCangLiuQin(FulInitialsBeloEnum.getValueByelEment("六亲",
					guaLiuQinEnum.getLiuQin(zhuGuaGanZhi.getCangDiZhi())).getAbbreviation());
			zhuGuaGanZhi.setCangNaYin(RelationMapConstant.JIAZI_NAYIN_MAP.get(cangGanZhi));
			//设置伏相关参数
			String fuGanZhi = guaFuGanZhiEnum.getFuGanZhi(index);
			zhuGuaGanZhi.setFuTianGan(fuGanZhi.substring(0, 1));
			zhuGuaGanZhi.setFuDiZhi(fuGanZhi.substring(1, 2));
			zhuGuaGanZhi.setFuLiuQin(FulInitialsBeloEnum.getValueByelEment("六亲",
					guaLiuQinEnum.getLiuQin(zhuGuaGanZhi.getFuDiZhi())).getAbbreviation());
			zhuGuaGanZhi.setFuNaYin(RelationMapConstant.JIAZI_NAYIN_MAP.get(fuGanZhi));
			//设置主要的干支关系
			String mainGanZhi = guaMainGanZhiEnum.getGanZhi(index);
			zhuGuaGanZhi.setTianGan(mainGanZhi.substring(0, 1));
			zhuGuaGanZhi.setDiZhi(mainGanZhi.substring(1));
			zhuGuaGanZhi.setLiuQin(FulInitialsBeloEnum.getValueByelEment("六亲",
					guaLiuQinEnum.getLiuQin(zhuGuaGanZhi.getDiZhi())).getAbbreviation());
			zhuGuaGanZhi.setNaYin(RelationMapConstant.JIAZI_NAYIN_MAP.get(mainGanZhi));
			zhuGuaGanZhi.setZhiWuXing(RelationMapConstant.WUXING_DIZHI.get(zhuGuaGanZhi.getDiZhi()));
			// 查询地支与月地支的邢冲合害关系
			List<String> monthSubscript = new ArrayList<>();
			String monthZhi = lunar.getMonthZhi();
			// 地支相刑
			String xing = RelationMapConstant.DIZHI_XIANGXING_MAP.get(monthZhi + zhuGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(xing)) {
				monthSubscript.add(xing);
			}
			// 地支六冲
			String chong = RelationMapConstant.DIZHI_LIUCHONG_MAP.get(monthZhi + zhuGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(chong)) {
				monthSubscript.add(chong);
			}
			// 地支相害
			String hai = RelationMapConstant.DIZHI_XIANGHAI_MAP.get(monthZhi + zhuGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(hai)) {
				monthSubscript.add(hai);
			}
			// 地支六合
			String he = RelationMapConstant.DIZHI_LIUHE_MAP.get(monthZhi + zhuGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(he)) {
				monthSubscript.add(he);
			}
			zhuGuaGanZhi.setMonthZhiSubscript(monthSubscript);
			// 查询地支与日地支的邢冲合害关系
			List<String> daySubscript = new ArrayList<>();
			String dayZhi = lunar.getDayZhi();
			// 地支相刑
			String dayXing = RelationMapConstant.DIZHI_XIANGXING_MAP.get(dayZhi + zhuGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(dayXing)) {
				daySubscript.add(dayXing);
			}
			// 地支六冲
			String dayChong = RelationMapConstant.DIZHI_LIUCHONG_MAP.get(dayZhi + zhuGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(dayChong)) {
				daySubscript.add(dayChong);
			}
			// 地支相害
			String dayHai = RelationMapConstant.DIZHI_XIANGHAI_MAP.get(dayZhi + zhuGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(dayHai)) {
				daySubscript.add(dayHai);
			}
			// 地支六合
			String dayHe = RelationMapConstant.DIZHI_LIUHE_MAP.get(dayZhi + zhuGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(dayHe)) {
				daySubscript.add(dayHe);
			}
			// 地支是否属于旬空
			String dayXunKong = lunar.getDayXunKong();
			if (dayXunKong.contains(zhuGuaGanZhi.getDiZhi())) {
				daySubscript.add("空");
			}
			zhuGuaGanZhi.setDayZhiSubscript(daySubscript);
			zhuGuaGanZhiList.add(zhuGuaGanZhi);
		}
		return zhuGuaGanZhiList;
	}

	/**
	 * 变卦的干支伏藏等详情
	 *
	 * @return
	 */
	private List<ChangeGuaGanZhi> getChangeGuaGanZhi(LiuYaoGua changeGua, Lunar lunar) {
		List<ChangeGuaGanZhi> changeGuaGanZhiList = new ArrayList<>();
		// 组合卦的下标
		String mergeIndex = String.valueOf(changeGua.getUpGua().getIndex()) + changeGua.getDownGua().getIndex();
		// 获取卦的主要天干等信息
		GuaMainGanZhiEnum guaChangeGanZhiEnum = GuaMainGanZhiEnum.getGanZhiByIndex(mergeIndex);
		if (guaChangeGanZhiEnum == null) {
			throw new ApiException("获取卦主要的干支失败");
		}
		// 获取卦的六亲关系
		GuaLiuQinEnum guaLiuQinEnum = GuaLiuQinEnum.getLiuQinByIndex(mergeIndex);
		if (guaLiuQinEnum == null) {
			throw new ApiException("获取卦的六亲失败");
		}
		for (int index = 1; index <= 6; index++) {
			ChangeGuaGanZhi changeGuaGanZhi = new ChangeGuaGanZhi();
			//设置主要的干支关系
			String changeGanzhi = guaChangeGanZhiEnum.getGanZhi(index);
			changeGuaGanZhi.setTianGan(changeGanzhi.substring(0, 1));
			changeGuaGanZhi.setDiZhi(changeGanzhi.substring(1));
			changeGuaGanZhi.setLiuQin(FulInitialsBeloEnum.getValueByelEment("六亲",
					guaLiuQinEnum.getLiuQin(changeGuaGanZhi.getDiZhi())).getAbbreviation());
			changeGuaGanZhi.setNaYin(RelationMapConstant.JIAZI_NAYIN_MAP.get(changeGanzhi));
			changeGuaGanZhi.setZhiWuXing(RelationMapConstant.WUXING_DIZHI.get(changeGuaGanZhi.getDiZhi()));
			// 查询地支与月地支的邢冲合害关系
			List<String> monthSubscript = new ArrayList<>();
			String monthZhi = lunar.getMonthZhi();
			// 地支相刑
			String xing = RelationMapConstant.DIZHI_XIANGXING_MAP.get(monthZhi + changeGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(xing)) {
				monthSubscript.add(xing);
			}
			// 地支六冲
			String chong = RelationMapConstant.DIZHI_LIUCHONG_MAP.get(monthZhi + changeGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(chong)) {
				monthSubscript.add(chong);
			}
			// 地支相害
			String hai = RelationMapConstant.DIZHI_XIANGHAI_MAP.get(monthZhi + changeGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(hai)) {
				monthSubscript.add(hai);
			}
			// 地支六合
			String he = RelationMapConstant.DIZHI_LIUHE_MAP.get(monthZhi + changeGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(he)) {
				monthSubscript.add(he);
			}
			changeGuaGanZhi.setMonthZhiSubscript(monthSubscript);
			// 查询地支与日地支的邢冲合害关系
			List<String> daySubscript = new ArrayList<>();
			String dayZhi = lunar.getDayZhi();
			// 地支相刑
			String dayXing = RelationMapConstant.DIZHI_XIANGXING_MAP.get(dayZhi + changeGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(dayXing)) {
				daySubscript.add(dayXing);
			}
			// 地支六冲
			String dayChong = RelationMapConstant.DIZHI_LIUCHONG_MAP.get(dayZhi + changeGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(dayChong)) {
				daySubscript.add(dayChong);
			}
			// 地支相害
			String dayHai = RelationMapConstant.DIZHI_XIANGHAI_MAP.get(dayZhi + changeGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(dayHai)) {
				daySubscript.add(dayHai);
			}
			// 地支六合
			String dayHe = RelationMapConstant.DIZHI_LIUHE_MAP.get(dayZhi + changeGuaGanZhi.getDiZhi());
			if (StringUtils.isNotEmpty(dayHe)) {
				daySubscript.add(dayHe);
			}
			// 地支是否属于旬空
			String dayXunKong = lunar.getDayXunKong();
			if (dayXunKong.contains(changeGuaGanZhi.getDiZhi())) {
				daySubscript.add("空");
			}
			changeGuaGanZhi.setDayZhiSubscript(daySubscript);
			changeGuaGanZhiList.add(changeGuaGanZhi);
		}
		return changeGuaGanZhiList;
	}

	/**
	 * 获取伏六亲肿主卦没有的六亲
	 *
	 * @param zhuGuaGanZhiList
	 * @return
	 */
	private List<String> getFuChangeColorLiuQin(List<ZhuGuaGanZhi> zhuGuaGanZhiList) {
		// 计算主卦中没有的六亲
		// 伏的六亲
		Set<String> fuLiuQinList =
				zhuGuaGanZhiList.stream().map(ZhuGuaGanZhi::getFuLiuQin).collect(Collectors.toSet());
		// 主要的六亲
		Set<String> mainLiuQinList =
				zhuGuaGanZhiList.stream().map(ZhuGuaGanZhi::getLiuQin).collect(Collectors.toSet());
		// 去掉主卦的六亲后看下是否剩余
		fuLiuQinList.removeAll(mainLiuQinList);
		return new ArrayList<>(fuLiuQinList);
	}

	/**
	 * 获取藏六亲肿主卦没有的六亲
	 *
	 * @param zhuGuaGanZhiList
	 * @return
	 */
	private List<String> getCangChangeColorLiuQin(List<ZhuGuaGanZhi> zhuGuaGanZhiList) {
		// 计算主卦中没有的六亲
		// 藏的六亲
		Set<String> cangLiuQinList =
				zhuGuaGanZhiList.stream().map(ZhuGuaGanZhi::getCangLiuQin).collect(Collectors.toSet());
		// 主要的六亲
		Set<String> mainLiuQinList =
				zhuGuaGanZhiList.stream().map(ZhuGuaGanZhi::getLiuQin).collect(Collectors.toSet());
		// 去掉主卦的六亲后看下是否剩余
		cangLiuQinList.removeAll(mainLiuQinList);
		return new ArrayList<>(cangLiuQinList);
	}

	/**
	 * 设置出参主卦的卦宫等
	 *
	 * @param liuYaoAllResp
	 * @param mainGua
	 */
	private void setMainGuaGong(LiuYaoAllResp liuYaoAllResp, LiuYaoGua mainGua, LiuYaoGua changeGua) {
		GuaGongEnum mainGuaGongEnum =
				GuaGongEnum.getGongByIndex(String.valueOf(mainGua.getUpGua().getIndex()) + mainGua.getDownGua().getIndex());
		liuYaoAllResp.setMainGuaGong(mainGuaGongEnum.getGuaGong());
		liuYaoAllResp.setMainGuaName(mainGuaGongEnum.getGuaName());
		liuYaoAllResp.setMainGuaLei(mainGuaGongEnum.getGuaLei());
		liuYaoAllResp.setGuaShen(mainGuaGongEnum.getGuaShen());
		GuaGongEnum changeGuaGongEnum =
				GuaGongEnum.getGongByIndex(String.valueOf(changeGua.getUpGua().getIndex()) + changeGua.getDownGua().getIndex());
		liuYaoAllResp.setChangeGuaName(changeGuaGongEnum.getGuaName());
		liuYaoAllResp.setChangeGuaGong(changeGuaGongEnum.getGuaGong());
		liuYaoAllResp.setChangeGuaLei(changeGuaGongEnum.getGuaLei());
		// 获取卦的主要天干等信息
		GuaMainGanZhiEnum guaMainGanZhiEnum =
				GuaMainGanZhiEnum.getGanZhiByIndex(String.valueOf(mainGua.getUpGua().getIndex()) + mainGua.getDownGua().getIndex());
		if (guaMainGanZhiEnum == null) {
			throw new ApiException("获取卦主要的干支失败");
		}
		// 设置世爻，应爻的位置
		liuYaoAllResp.setShiYaoIndex(guaMainGanZhiEnum.getShiYaoIndex());
		liuYaoAllResp.setYingYaoIndex(guaMainGanZhiEnum.getYingYaoIndex());
	}

	/**
	 * 计算两个卦的归藏卦
	 *
	 * @param gua1
	 * @param gua2
	 * @return
	 */
	private BaseGuaEnum getGuiCangGua(BaseGuaEnum gua1, BaseGuaEnum gua2) {
		// 获取主卦上下卦的爻
		String mainUpYaos = gua1.getYaos();
		String mainDownYaos = gua2.getYaos();
		char guiCangChar1 = guiCangCompute(mainUpYaos.charAt(0), mainDownYaos.charAt(0));
		char guiCangChar2 = guiCangCompute(mainUpYaos.charAt(1), mainDownYaos.charAt(1));
		char guiCangChar3 = guiCangCompute(mainUpYaos.charAt(2), mainDownYaos.charAt(2));
		// 根据三个爻获取主卦的归藏
		BaseGuaEnum mainGuiCangGua = BaseGuaEnum.findGuaByYao(String.valueOf(guiCangChar1),
				String.valueOf(guiCangChar2), String.valueOf(guiCangChar3));
		return mainGuiCangGua;
	}

	/**
	 * 归藏计算
	 *
	 * @param yao1
	 * @param yao2
	 * @return
	 */
	private char guiCangCompute(char yao1, char yao2) {
		if (yao1 == GuaConstant.YANG) {
			if (yao2 == GuaConstant.YANG) {
				return GuaConstant.YIN;
			} else {
				return GuaConstant.YANG;
			}
		} else {
			if (yao2 == GuaConstant.YANG) {
				return GuaConstant.YANG;
			} else {
				return GuaConstant.YIN;
			}
		}
	}
}
